package com.xb.cloud.gateway.core;

import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.xb.cloud.common.util.StringUtils;
import com.xb.cloud.gateway.client.ClientInfo;
import com.xb.cloud.gateway.client.Context;
import com.xb.cloud.gateway.client.RequestInfo;

/**
 * 
 * @ClassName: BuildXBContext
 * @Description:进一步封装请求上下文
 * @author: 鲜备科技
 * @date: 2017年12月19日 下午5:07:46
 * 
 * @Copyright: 2017 www.xianbeitech.com Inc. All rights reserved.
 *
 */
public class BuildXBContext {

	private static final String UPLOAD_DIRECTORY = "var/www/webapps/upload";
	// 上传配置
	private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3; // 3MB
	private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB
	private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB

	public static void execute(Context context) {

		HttpServletRequest httpRequest = context.getHttpRequest();
		// 业务参数反序列化;
		@SuppressWarnings("unchecked")
		Enumeration<String> params = httpRequest.getParameterNames();
		Map<String, String> bizPara = new TreeMap<String, String>();

		// 构造请求参数map
		if (params != null) {
			while (params.hasMoreElements()) {
				String key = params.nextElement();
				String value = httpRequest.getParameter(key);
				bizPara.put(key, value);
			}
		}

		List<FileItem> reqFileItems = new ArrayList<>();
		if (httpRequest != null && ServletFileUpload.isMultipartContent(httpRequest)) {
			// 处理已formData或上传时的参数处理
			// 配置上传参数
			DiskFileItemFactory factory = new DiskFileItemFactory();
			// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中
			factory.setSizeThreshold(MEMORY_THRESHOLD);
			// 设置临时存储目录
			File repository = new File(UPLOAD_DIRECTORY);
			factory.setRepository(repository);
			if (!repository.exists()) {
				repository.mkdirs();
			}

			ServletFileUpload upload = new ServletFileUpload(factory);
			upload.setHeaderEncoding("UTF-8");
			Map<String, String> multipartParameters = new HashMap<String, String>();
			try {
				List<FileItem> fileItems = upload.parseRequest(httpRequest);
				for (FileItem fileItem : fileItems) {
					if (fileItem.isFormField()) {
						String value = fileItem.getString("UTF-8");
						String curParam = multipartParameters.get(fileItem.getFieldName());
						if (curParam == null) {
							multipartParameters.put(fileItem.getFieldName(), value);
						} else {
							String newParam = new StringBuffer(curParam).append(",").append(value).toString();
							multipartParameters.put(fileItem.getFieldName(), newParam);
						}
					} else {
						reqFileItems.add(fileItem);
					}
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}

			bizPara.putAll(multipartParameters);
		}

		parseRequestHeader(context, bizPara, reqFileItems);

	}

	private static void parseRequestHeader(Context context, Map<String, String> bizPara, List<FileItem> reqFileItems) {
		String companyToken = context.getHttpRequest().getHeader("companyToken");
		if (StringUtils.isEmpty(companyToken)) {
			String domainName = context.getHttpRequest().getServerName();
			// TODO:后期域名需要通过网关的配置中心动态配置，而且支持二，三，四。。。。级别域名
			// TODO:company_id最好不要暴露到外面，前期先这样，后续在脱敏
			String companyId = "1";
			context.getHttpResponse().setHeader("companyToken", companyId);
			context.setCompanyId(Long.valueOf(companyId));
		} else {
			context.setCompanyId(Long.valueOf(companyToken));
		}

		ClientInfo clientInfo = null;
		String provinceId = "";
		String cityId = "";
		String userToken = "";
		String merchantUserToken = "";
		String userAgent = "";
		@SuppressWarnings("unchecked")
		Enumeration<String> headers = context.getHttpRequest().getHeaderNames();
		if (headers != null) {
			while (headers.hasMoreElements()) {
				String key = headers.nextElement();
				String value = context.getHttpRequest().getHeader(key);
				if ("userToken".equalsIgnoreCase(key)) {
					userToken = value;
				} if ("merchantUserToken".equalsIgnoreCase(key)) {
					merchantUserToken = value;
				} else if ("provinceId".equalsIgnoreCase(key)) {
					provinceId = value;
				} else if ("cityId".equalsIgnoreCase(key)) {
					cityId = value;
				} else if ("User-Agent".equalsIgnoreCase(key)) {
					userAgent = value;
				}
				// 电商云一期不考虑clientInfo,主要是后期预留字段
				else if (key.equalsIgnoreCase("clientInfo")) {

					Map<String, String> clientInfoMap;
					try {
						clientInfoMap = JSON.parseObject(value, new TypeReference<Map<String, String>>() {
						});
					} catch (Exception e) {
						clientInfoMap = new HashMap<String, String>();
					}

					clientInfo = new ClientInfo(clientInfoMap.get("clientAppVersion"),
							clientInfoMap.get("clientSystem"), clientInfoMap.get("clientVersion"),
							clientInfoMap.get("deviceCode"), clientInfoMap.get("latitude"),
							clientInfoMap.get("longitude"), clientInfoMap.get("traderName"),
							clientInfoMap.get("unionKey"), clientInfoMap.get("nettype"), clientInfoMap.get("iaddr"),
							context.getRequestIp(), clientInfoMap.get("phoneType"), clientInfoMap.get("imei"),
							clientInfoMap.get("abtest"), clientInfoMap.get("softfp"));
					clientInfo.setIsRoot(clientInfoMap.get("isRoot"));
					clientInfo.setIdfa(clientInfoMap.get("idfa"));
					clientInfo.setDeviceToken(clientInfoMap.get("deviceToken"));
				}
			}
		}

		context.setRequestInfo(new RequestInfo(clientInfo, userToken, provinceId, cityId, userAgent, bizPara));
		context.getRequestInfo().setFileItems(reqFileItems);
		context.getRequestInfo().setMerchantUserToken(merchantUserToken);
	}

}
